﻿#include "ssLineBuffer.h"
#include "../ssAssert.h"
#include <memory.h>

namespace StarSeeker
{

ssLineBuffer::ssLineBuffer()
	:m_count(0), m_writeOffset(SS_INVAILD_UINT)
{
}

ssLineBuffer::ssLineBuffer(const ssLineBuffer &oc)
	: m_count(0), m_writeOffset(SS_INVAILD_UINT)
{
	CopyFrom(oc);
}

ssLineBuffer::~ssLineBuffer()
{
	Clear();
}

void ssLineBuffer::operator=(const ssLineBuffer &oc)
{
	CopyFrom(oc);
}

bool ssLineBuffer::Init(ulint size)
{
	if (size>0)
	{
		m_count = 0;
		return m_buffer.Init(size, MEM_MGR_NEW);
	}
	return false;
}

bool ssLineBuffer::FormatIn(char *data, ulint size)
{
	if (size > 0)
	{
		char err = 0;
		ulint readSize = 0;
		ulint count = 0;
		while (err==0)
		{
			ulint* len = (ulint*)(data + readSize);
			++count;
			readSize += *len + cg_ulint_size;
			if (readSize == size)
			{
				err = 1;
			}
			else if (readSize > size)
			{
				err = 2;
			}
		}
		if (err == 1)
		{
			if (m_buffer.Init(data, size))
			{
				m_count = count;
				return m_buffer.SetSize(size);
			}
		}
	}
	return false;
}

bool ssLineBuffer::PushBack(const void *data, ulint len)
{
	bool ret = false;
	if (m_buffer.MemType() < MEM_MGR_NEW && len + cg_ulint_size + m_buffer.Size() > m_buffer.MaxSize())
	{
		SS_ASSERT_DEBUG(false);
		return false;
	}
	ret = m_buffer.Write(&len, cg_ulint_size);
	if (ret)
	{
		++m_count;
		if (len > 0)
		{
			ret = m_buffer.Write(data, len);
		}
	}
	return ret;
}

StarSeeker::ulint ssLineBuffer::Count() const
{
	return m_count;
}

StarSeeker::ulint ssLineBuffer::Size() const
{
	return m_buffer.Size();
}

StarSeeker::ulint ssLineBuffer::RemainSize()
{
	return m_buffer.ResidueSize();
}

const char* ssLineBuffer::Buf() const
{
	return m_buffer.Buf();
}

void ssLineBuffer::Clear()
{
	m_count = 0;
	m_buffer.Clear();
}

void ssLineBuffer::Empty()
{
	m_count = 0;
	m_buffer.Empty();
}

ssLineBuffer::Iterator ssLineBuffer::Begin()
{
	Iterator itr;
	if (m_buffer.Size() > 0)
	{
		itr.pData = m_buffer.Buf() + cg_ulint_size;
		itr.nSize = *reinterpret_cast<ulint*>(m_buffer.Buf());
		itr.traversalCount = 1;
	}
	return itr;
}

bool ssLineBuffer::Next(Iterator& itr)
{
	if (itr.traversalCount >= m_count || m_buffer.Size() == 0)
	{
		itr.Clear();
		return false;
	}

	ulint lastSize = itr.nSize;
	if (lastSize>m_buffer.Size())
	{
		SS_ASSERT_DEBUG(false);
		itr.Clear();
		return false;
	}
	itr.nSize = *reinterpret_cast<ulint*>(itr.pData+lastSize);
	itr.pData = itr.pData + lastSize + cg_ulint_size;
	++itr.traversalCount;
	return true;
}

void ssLineBuffer::BeginWrite()
{
	m_writeOffset = m_buffer.Size();
	const ulint writeSize = 0;
	if (!m_buffer.Write(&writeSize, cg_ulint_size))
	{
		m_writeOffset = SS_INVAILD_UINT;
	} 
}

void ssLineBuffer::Write(const void* buf, ulint len)
{
	if (m_writeOffset != SS_INVAILD_UINT)
	{
		m_buffer.Write(buf, len);
	}
}

void ssLineBuffer::WriteStruct(const void* buf, ulint len)
{
	if (m_writeOffset != SS_INVAILD_UINT)
	{
		u32 len2 = (u32)len;
		if (m_buffer.MemType() < MEM_MGR_NEW && len + cg_u32_size + m_buffer.Size() > m_buffer.MaxSize())
		{
			SS_ASSERT_DEBUG(false);
			return;
		}
		if (m_buffer.Write(&len2, cg_u32_size) && len > 0)
		{
			m_buffer.Write(buf, len);
		}
	}
}

void ssLineBuffer::EndWrite()
{
	if (m_writeOffset != SS_INVAILD_UINT)
	{
		ulint totalSize = m_buffer.Size();
		ulint writeSize = totalSize - m_writeOffset;
		if (writeSize >= cg_ulint_size && writeSize <= totalSize)
		{
			++m_count;
			ulint* plen = reinterpret_cast<ulint*>(m_buffer.Buf() + m_writeOffset);
			*plen = writeSize - cg_ulint_size;
		}
		m_writeOffset = SS_INVAILD_UINT;
	}
}

void ssLineBuffer::CopyFrom(const ssLineBuffer &oc)
{
	Clear();
	m_buffer = oc.m_buffer;
	m_count = oc.m_count;
}

}
